/////precompiled////////
#include "precompiled.h"
////////////////////////


#include "frm_control_TParaEdit.h"

using namespace frm;
using namespace control;

// TParaEdit //////////////////////////////////////////////////////////////////

//
void TParaEdit::TStyle::SetFromParent(frm::TStyle *Parent_)
{
  if (!Parent_) {
    return;
  }

  TStyle *Parent = dynamic_cast<TStyle*>(Parent_);
  frm::TStyle::SetFromParent(Parent);
  Normal.SetFromParent(&Parent->Normal);

  //Para.SetFromParent(&Parent->Para);
}

//
svl::TInfoParam TParaEdit::TStyle::AddInfoTo(svl::TInfoParam Info)
{
  return frm::TStyle::AddInfoTo(Info)
   .Add("Normal",Normal)
   //.Add("Para",Para)
  ;
}

//
TParaEdit::TParaEdit(TWindow &Window) : TPanel(Window)
{
  static TStyle Style; SetStyle(Style);

  wAlignChildrenPara = new geometry::TBegin;
  
  Width_Fixed(200).Height_Fixed(200)
   .DirectChildren_Vert()
   .WAlignChildren_Begin().HAlignChildren_Begin();

  SetEnFormatting();
}

//
TParaEdit::~TParaEdit()
{
  delete wAlignChildrenPara;
}

//
void TParaEdit::WAlignChildrenPara(geometry::TAlignChildren &V)
{
  delete wAlignChildrenPara; wAlignChildrenPara = V.New();
}

//
void TParaEdit::SetAttrPara(TPara *Para)
{
  Para->SetEnProcChangeWidth(false);
  Para->SetEnFormatting(enFormatting);

  Para->Width_Parent().Height_ChildrenSum()
   .DirectChildren_Vert()
   .WAlignChildren_Begin().HAlignChildren_Begin();

  Para->FirstLine->Width_Parent().Height_ChildrenMax()
   .DirectChildren_Horz()
   .WAlignChildren(*wAlignChildrenPara).HAlignChildren_BeginBase();
}

//
void TParaEdit::AddPara(svl::TString V,TString::TStyle *StringStyle)
{
  BeginPaint();
  
  TPara *Para = NewPara(); AddChildLast(Para,true);

    TString *S = new TString(GetWindow()); Para->FirstLine->AddChildLast(S,true);
    if (StringStyle) { S->SetStyle(*StringStyle); }
    S->SetValue(V);
    
  EndPaint();  
}

//
void TParaEdit::LoadFromText(svl::TText &Text,TString::TStyle *StringStyle)
{
  BeginPaint();
  
  DeleteChildren(); if (Text.CountLines()) for (int N = 0; N < Text.CountLines(); N++)
  {
    TPara *Para = NewPara(); AddChildLast(Para,true);

      TString *S = new TString(GetWindow()); Para->FirstLine->AddChildLast(S,true);
      if (StringStyle) { S->SetStyle(*StringStyle); }
      S->SetValue(Text.GetLine(N));
  }
  else
  {
    TPara *Para = NewPara(); AddChildLast(Para,true);

      TString *S = new TString(GetWindow()); Para->FirstLine->AddChildLast(S,true);
      if (StringStyle) { S->SetStyle(*StringStyle); }
  }
  
  EndPaint();
}

//
void TParaEdit::SaveToText(svl::TText &Text)
{
  Text.Clear(); for (int Npara = 0; Npara < GetChildrenCount(); Npara++)
  {
    TComponent &Child = GetChild(Npara);
    TPara *Para = dynamic_cast<TPara*>(&Child); if (Para)
    {
      TLine *Line = Para->FirstLine;
      TComponentArray Str; Line->SearchChildrenByType(TString::TType(),Str);
      
      if (Str.Count())
      {
        svl::TString SLine; for (int Nstr = 0; Nstr < Str.Count(); Nstr++)
        {
          TString &String = (TString&)Str.Get(Nstr);
          SLine << String.GetValue();
        }
        Text.AddLine(SLine);
      }
    }
  }
}

//
TPara *TParaEdit::NewPara()
{
  TPara *Para = new TPara(GetWindow());
  //Para->SetStyle(style->Para);
  SetAttrPara(Para);
  return Para;
}

//
void TParaEdit::TComponent_KeyboardKey(grf::TKeyboardKey &KeyboardKey)
{
  if (KeyboardKey.State == grf::TKeyboardKey::EState_Down)
  {
    switch (KeyboardKey.Key)
    {
      case VK_UP: case VK_DOWN:
      {
        TPanel *CurrFocus = Focus_GetEnter();

        TPanel *CurrLine = static_cast<TPanel*>(
          CurrFocus->SearchThisOrParent(TLine::TType())
        );
        if (!CurrLine) { break;}

        TPanel *NewLine = static_cast<TPanel*>(
          KeyboardKey.Key == VK_UP
            ? SearchPrevChild(TLine::TType(),CurrLine)
            : SearchNextChild(TLine::TType(),CurrLine)
        );
        if (!NewLine) { break;}

        TPanel *NewFocus = NewLine->SearchNextChild
          (TString::TType(),NULL);
        if (!NewFocus) { break;}

        NewFocus->Focus_EnterByX(Focus_GetX());
      }
      return;

      case VK_PRIOR: case VK_NEXT:
      {
        TPanel *CurrFocus = Focus_GetEnter();

        TPanel *CurrLine = static_cast<TPanel*>(
          CurrFocus->SearchThisOrParent(TLine::TType())
        );
        if (!CurrLine) { break;}

        TGeometryRect ThisGRect; if ( !GetWindow().CalcGeometryRect(this,ThisGRect) )
          { break;}

        TPanel *NewLine = static_cast<TPanel*>(
          KeyboardKey.Key == VK_PRIOR
            ? SearchPrevChildInHeight(ThisGRect,CurrLine)
            : SearchNextChildInHeight(ThisGRect,CurrLine)
        );
        if (!NewLine) { break;}

        TPanel *NewFocus = NewLine->SearchNextChild
          (TString::TType(),NULL);
        if (!NewFocus) { break;}

        NewFocus->Focus_EnterByX(Focus_GetX());
      }
      return;

      case VK_RETURN: 
      {
        TPanel *CurrFocus = Focus_GetEnter();

        TLine *CurrLine = dynamic_cast<TLine*>
          ( CurrFocus->SearchThisOrParent(TLine::TType()) );
        if (!CurrLine) { break;}

        TPara *CurrPara = dynamic_cast<TPara*>
          ( CurrLine->SearchParent(TPara::TType()) );
        if (!CurrPara) { break;}

        TMergeSplit MS;
          MS.Focus = Focus_GetEnter();
          MS.Pos   = Focus_GetPos();
        
        TPara *NextPara = NewPara();
          NextPara->GetGeometry().CopyFrom(CurrPara->GetGeometry());
          NextPara->SetStyle(CurrPara->GetStyle());
       
          //NextPara->FirstLine->SetStyle(CurrLine->GetStyle());
          NextPara->FirstLine->GetGeometry().CopyFrom(CurrLine->GetGeometry());
          
        TBeginPaint BeginPaint(this);
        
        bool IsSplit = false;
        {
          TPara::TTempDisableFormatting D1(CurrPara);
          TPara::TTempDisableFormatting D2(NextPara);
        
          IsSplit = CurrLine->SplitInComponentPos(MS,*NextPara->FirstLine,CurrFocus,Focus_GetPos()); if (IsSplit)
          {
            //{ /*TDisableUpdate D(this);*/ AddChildAfter(NextPara,CurrPara,true); }
            
            int NCurrLine = CurrPara->GetNChild(CurrLine); if (NCurrLine + 1 < CurrPara->GetChildrenCount())
              { CurrPara->MoveChildrenTo(NCurrLine+1,CurrPara->GetChildrenCount()-1,1,NextPara); }
          }
        } 
        if (IsSplit) {
          AddChildAfter(NextPara,CurrPara,true);
          //CurrPara->Formatting();
          CurrPara->CalcAllSize();
          CurrPara->ReupdateSize();
          NextPara->Formatting();
          //ReupdateSize();
          //CurrPara->Formatting();

          //GetGeometry().CalcAll();  
          //NextPara->GetGeometry().CalcAll(); 
          //CurrPara->GetGeometry().ReupdateSize();
          //NextPara->GetGeometry().ReupdateSize(); 
          
          if (ThisIsParent(MS.Focus)) {
            if (MS.Focus->Focus_EnterByPos(MS.Pos)) { 
              MS.Focus->Focus_FixCaretX(); 
            }
          }
        }
        else { 
          delete NextPara;
        }
      }
      return;

      case VK_DELETE: if (KeyboardKey.Shift.IsEmpty())
      {
        TPanel *CurrFocus = Focus_GetEnter();

        TLine *CurrLine = dynamic_cast<TLine*>
          ( CurrFocus->SearchThisOrParent(TLine::TType()) );
        if (!CurrLine) { break;}

        TPara *CurrPara = dynamic_cast<TPara*>
          ( CurrLine->SearchParent(TPara::TType()) );
        if (!CurrPara) { break;}

        int NCurrLine = CurrPara->GetNChild(CurrLine); if (NCurrLine + 1 < CurrPara->GetChildrenCount())
          { break; }
          
        TPara *NextPara = dynamic_cast<TPara*>
          ( SearchNextChild(TPara::TType(),CurrPara) );
        if (!NextPara) { break;}

        if (NextPara->GetChildrenCount() == 0)
          { break; }
                  
        TBeginPaint BeginPaint(this);
        NextPara->MoveChildrenTo(0,NextPara->GetChildrenCount()-1,NCurrLine+1,CurrPara);
        DeleteChild(NextPara);
        CurrPara->Formatting();
      }
      return;

      case VK_BACK: {
        TPanel *CurrFocus = Focus_GetEnter();

        TLine *CurrLine = dynamic_cast<TLine*>( 
          CurrFocus->SearchParent(TLine::TType()) 
        );
        if (!CurrLine) { 
          break;
        }
        
        TPara *CurrPara = dynamic_cast<TPara*>( 
          CurrLine->SearchParent(TPara::TType()) 
        );
        if (!CurrPara) { 
          break;
        }

        if (CurrLine != CurrPara->FirstLine) { 
          break; 
        }

        TPara *PrevPara = dynamic_cast<TPara*>( 
          SearchPrevChild(TPara::TType(),CurrPara) 
        );
        if (!PrevPara) { 
          break;
        }

        TBeginPaint BeginPaint(this);
        CurrPara->MoveChildrenTo(
          0,CurrPara->GetChildrenCount()-1,PrevPara->GetChildrenCount(),PrevPara
        );

        GetWindow().PanelDeletor.Add(this,CurrPara); 
        //DeleteChild(CurrPara);
        PrevPara->Formatting();
      }
      return;
    }
  }
  TPanel::TComponent_KeyboardKey(KeyboardKey);
}

//
void TParaEdit::TComponent_AfterAddChild(TComponent *Child)
{
  TPanel::TComponent_AfterAddChild(Child);

  if (!dynamic_cast<TPara*>(Child)) { 
    Except("TComponent_AfterAddChild[!dynamic_cast<TPara*>(Child)]");
  }
}

//
void TParaEdit::TComponent_AfterChangeWidth(int OldVal,int NewVal)
{
  TPanel::TComponent_AfterChangeWidth(OldVal,NewVal);

  if (OldVal == NewVal)
    { return;}
  if (svl::TPStack::IsTop(this))
    { return;}
  svl::TPStack PStack(this);
  
  if (!IsVisibleInParents())
    { return;}
  TBeginPaint P(this); 
  
  for (int N = 0; N < GetChildrenCount(); N++) {
    TPara *Para = dynamic_cast<TPara*>(&GetChild(N)); 
    if (Para) { 
      Para->Formatting(GetClientWidth());
    }
  }
}

//
void TParaEdit::TComponent_InheritStyleFrom(TTableOfStyles &ParentStyles)
{ 
  TStyle *Style = dynamic_cast<TStyle*>(ParentStyles.SearchByEqualType(TStyle::TType())); if (Style) {
    SetStyle(*Style);
  }
}
